import os
import struct
from dash import Dash, dash_table, dcc, html, callback, Input, Output, State
import dash
import dash_bootstrap_components as dbc
import psycopg2.extras
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from Units import QUnits

dash.register_page(__name__, path='/execise')

class TDXLoader:
    def __init__(self):
        unit = QUnits()
        # TDX_DIR 为通达信根目录
        self.TDX_DIR = os.path.dirname(unit.XML2ObjFromFile('./setting.xml').setting.tdx.path)

    def resolve(self, *args, **kwargs):
        return os.path.join(self.TDX_DIR, *args, **kwargs)

    # 读取K线源文件
    def _read_kline(self, filepath, pack='lllllfll'):
        with open(filepath, "rb") as f:
            usecols = "trade_date open high low close amount vol openinterest".split()
            buffers = []
            while True:
                buffer = f.read(32)
                if not buffer:
                    break
                buffer = struct.unpack(pack, buffer)
                if(pack == 'lllllfll'):
                    buffers.append(buffer)
                else:
                    buffers.append((self.get_date_str(buffer[0], buffer[1]), buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8]))
            kline = pd.DataFrame(buffers, columns=usecols)
        kline["trade_date"] = kline["trade_date"].astype(str)
        price_columns = ["open", "high", "low", "close"]
        kline[price_columns] = kline[price_columns].apply(lambda x: x / 100)
        return kline

    # 根据二进制前两段拿到日期分时
    def get_date_str(self, h1, h2) -> str:  # H1->0,1字节; H2->2,3字节;
        year = math.floor(h1 / 2048) + 2004  # 解析出年
        month = math.floor(h1 % 2048 / 100)  # 月
        day = h1 % 2048 % 100  # 日
        hour = math.floor(h2 / 60)  # 小时
        minute = h2 % 60  # 分钟
        if hour < 10:  # 如果小时小于两位, 补0
            hour = "0" + str(hour)
        if minute < 10:  # 如果分钟小于两位, 补0
            minute = "0" + str(minute)
        return str(year) + "-" + str(month) + "-" + str(day) + " " + str(hour) + ":" + str(minute)

    # 获取日K线数据
    def get_kline_daily(self, ts_code, cycle=None):
        if(cycle in ('1h', '30m', '15m', '5m')):
            filename = ts_code.split(".")[1] + ts_code.split(".")[0] + ".lc5"
            filepath = self.resolve("vipdoc", ts_code.split(".")[1], "fzline", filename)
            pack = 'HHffffllf'
        elif(cycle == '1m'):
            filename = ts_code.split(".")[1] + ts_code.split(".")[0] + ".lc1"
            filepath = self.resolve("vipdoc", ts_code.split(".")[1], "minline", filename)
            pack = 'HHffffllf'
        else:
            filename = ts_code.split(".")[1] + ts_code.split(".")[0] + ".day"
            filepath = self.resolve("vipdoc", ts_code.split(".")[1], "lday", filename)
            pack = 'lllllfll'
        kline = self._read_kline(filepath, pack)
        kline["ts_code"] = ts_code
        kline.index = pd.to_datetime(kline["trade_date"])
        kline.index.name = "index"
        kline = kline.rename(columns={"vol": "volume"})
        usecols = (
            "ts_code trade_date open high low close amount volume openinterest".split()
        )
        return kline[usecols]

def getPiedata():
    unit = QUnits()
    setting = unit.XML2ObjFromFile('./setting.xml').setting
    try:
        conn = unit.dbConnect(setting.pgsql)
        cursor = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
        cursor.execute('SELECT stock_label, capitalized * number AS cost, market_value * number AS curr FROM trading.owner_stock_view WHERE stock_code IS NOT NULL')
        df = pd.DataFrame(cursor.fetchall())
    except Exception as e:
        logging.warning(str(e))
    finally:
        unit.dbDisconnect(conn)
    return df

def layout():
    loader = TDXLoader()
    dKline = loader.get_kline_daily("600645.sh", '1d')
    dKfig = go.Candlestick(x=dKline['trade_date'], open=dKline['open'], high=dKline['high'], low=dKline['low'], close=dKline['close'])
    fig1 = px.pie(getPiedata(), values='cost', names='stock_label', title='原始成本分布图')
    fig2 = px.pie(getPiedata(), values='curr', names='stock_label', title='限价资产分布图')
    fig2.update_traces(textposition='inside', textinfo='percent+label')
    return dbc.Container([
        html.Div(
            children=[html.Div(className='col-md-6',
                               children=html.Div(className='panel panel-primary',
                                                 children=[html.Div(className='panel-heading', children='日线'),
                                                           html.Div(children=dcc.Graph(figure={'data': [dKfig]}), className='panel-body')]
                                                 )
                               ),
                      html.Div(className='col-md-6',
                               children=html.Div(className='panel panel-success',
                                                  children=[html.Div(className='panel-heading', children='小时线'),
                                                            html.Div(children=dcc.Graph(figure=fig2), className='panel-body')]
                                                 )
                               )
                      ],
            className='row'),
        html.Div(
            children=[html.Div(className='col-md-6',
                               children=html.Div(className='panel panel-warning',
                                                 children=[html.Div(className='panel-heading', children='5分钟线'),
                                                           html.Div(children=dcc.Graph(figure=fig1),
                                                                    className='panel-body')]
                                                 )
                               ),
                      html.Div(className='col-md-6',
                               children=html.Div(className='panel panel-danger',
                                                 children=[html.Div(className='panel-heading', children='15分钟线'),
                                                           html.Div(children=dcc.Graph(figure=fig2),
                                                                    className='panel-body')]
                                                 )
                               )
                      ],
            className='row'),
    ], fluid=True)